/*
 * Roberto Andrino 12413
 * Iván Concuá 12352
 * Gabriela Manrique 12460
 * José Roberto Ruano 12101
 * Luis José Pinillos 12523
 * 
 * Clase principal de la aplicacion de android. 
 * Instrucciones de uso: Cuando se ejecuta la aplicacion aparece
 * en pantalla tres botones y dos text fields. El boton "Show map"
 * muestra un mapa de la UVG con tags para cada edificio cuando se
 * se presiona. El segundo boton indica las coordenadas (latitud, longitud)
 * del usuario. El tercer boton (get distance) muestra la distancia de la ubicacion
 * actual del usuario al edificio indicado por el primer text field, con
 * una flecha que apunta a donde debe caminar el usuario. Si ambos
 * text fields tienen el nombre de un edificio, el tercer boton muestra
 * la distancia entre los edificios indicados y cual es el edificio central 
 * de la UVG.
 */

package com.uvg.camara;

import java.io.IOException;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import android.location.Location;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.TextView;

public class MainActivity extends Activity implements SensorEventListener, SurfaceHolder.Callback{

	/* se crean los objetos de las clases necesarias */
	private Matriz matriz; // matriz con un grafo
	private Camera camera; // para abrir la camara
	private SurfaceView surfaceView;
	private SurfaceHolder surfaceHolder;
	private boolean previewing = false;
	private LayoutInflater controlInflater = null;
	private double bearing = 0;
	private float heading = 0;
	
	private EditText userInput; //entradas de texto
	private EditText userInput2;
	private Button btnShowLocation; // botones 
	private Button btnShowDistance;
	private Button btnShowmap;
	
	// GPSTracker class
	private GPSTracker gps; // para ubicar al usuario
	
	private Boolean pointArrow; 
	
	// imagen de la flecha
    private ImageView image;

    // angulo de la flecha
    private float currentDegree = 0f;

    // device sensor manager
    private SensorManager mSensorManager;
	
    // lista con las longitudes de los edificios
	private final double[] longitudes = 
		{-90.488800406456, -90.49002885818481, -90.49029976129532, -90.48994839191437, -90.48996984958649,
		 -90.49023538827896, -90.4895943403244, -90.48921346664429, -90.4890176653862, -90.48887550830841,
		 -90.48864752054214, -90.48914104700089, -90.48936903476715, -90.48825860023499, -90.48843562602997, -90.4167};
	
	// lista con las latitudes de los edificios
	private final double[] latitudes =
		{14.604647298301906, 14.604688826992607, 14.60502884285263, 14.605072967009662, 14.605220912648042,
		 14.605197552817016, 14.604465610187932, 14.60489387478792, 14.605065180394353, 14.605233890330853,
		 14.605459701889568, 14.604257966445275, 14.60405551360738, 14.605457106355619, 14.605013269618619, 14.55};
	
	// lista con los nombres de los edificios
	private final String[] edificios =
		{"A", "B", "C", "Ca", "C1", "D", "E", "F", "G", "H", "I", "II1", "II2", "J", "K", "SJP"};
	
    /* Se llama cuando se crea la actividad. */
	@Override
    public void onCreate(Bundle savedInstanceState) {
		/* se inicia la actividad mostrando todo el GUI */
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); // layout indicado por activity_main.xml
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        
        /* para abrir la camara para verla en pantalla */
        getWindow().setFormat(PixelFormat.UNKNOWN);
        surfaceView = (SurfaceView)findViewById(R.id.camerapreview);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);
        
        /* para poner otro layout (control.xml) encima de la actividad principal */
        controlInflater = LayoutInflater.from(getBaseContext());
        View viewControl = controlInflater.inflate(R.layout.control, null);
        LayoutParams layoutParamsControl = new LayoutParams(LayoutParams.MATCH_PARENT, 
        	LayoutParams.MATCH_PARENT);
        this.addContentView(viewControl, layoutParamsControl);
        
        matriz = new Matriz();
        
        // text fields para que el usuario ingrese datos
        userInput = (EditText) findViewById(R.id.editText1);
        
        userInput2 = (EditText) findViewById(R.id.editText2);
        
        // imagen de la flecha 
        image = (ImageView) findViewById(R.id.imageViewArrow);

        // inicializa los sensores del dispositivo android
        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        
        // boton que muestra el mapa
        btnShowmap = (Button) findViewById(R.id.btnShowmap);
        // show location button click event
        btnShowmap.setOnClickListener(new View.OnClickListener() {
        	
			@Override
			public void onClick(View arg0) {		
				// cuando se presiona este boton, se llama este metodo
				hideSoftKeyboard(MainActivity.this, arg0);
				Intent browserIntent = 
                        new Intent(Intent.ACTION_VIEW, Uri.parse("http://goo.gl/maps/idHg4"));
				startActivity(browserIntent);		
				// se abre una pagina de google  maps en el browser
				
				image.setVisibility(View.INVISIBLE);
			}
		});

        // boton que muestra la ubicacion actual
        btnShowLocation = (Button) findViewById(R.id.btnShowlocation);     
        // show location button click event
        btnShowLocation.setOnClickListener(new View.OnClickListener() {
        	
			@Override
			public void onClick(View arg0) {		
				// se inicializa el objeto gps de GPSTracker.java
		        gps = new GPSTracker(MainActivity.this);
		       
				// se revisa si se puede habilitar el gps
		        if(gps.canGetLocation()){
		        	
		        	double latitude = gps.getLatitude();
		        	double longitude = gps.getLongitude();
		        	
		        	// mensaje que muestra la ubicacion del usuario
		        	Toast.makeText(getApplicationContext(), "Your Location is - \nLat: " + latitude + 
		        			"\nLong: " + longitude, Toast.LENGTH_LONG).show();	
		        }else{
		        	// no se puede obtener la ubicacion actual
		        	// se le pide al usuario que active sus sensores de gps
		        	gps.showSettingsAlert();
		        	
		        	image.setVisibility(View.INVISIBLE);
		        }
		        
		        hideSoftKeyboard(MainActivity.this, arg0); // se esconde el teclado
			}
		});
        
        btnShowDistance = (Button) findViewById(R.id.btnShowdistance);
        // show location button click event
        btnShowDistance.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View arg0) {		
				// create class object
		        gps = new GPSTracker(MainActivity.this);
		        pointArrow = true; 
		        //check if EditText has text
		        if(userInput.getText().toString().equals(""))
		        {
		        	gps.showInputAlert();
		        	image.setVisibility(View.INVISIBLE);
		        }else{
		        	
		        	// check if GPS enabled		
			        if(gps.canGetLocation()){		        	
			        	double lat1 = -9999;
		        		double lon1 = -9999;
		        		String edificio2 = "";
		        		
		        		// se revisa si el input del usuario es
		        		// un edificio valido
			        	if(!userInput2.getText().toString().equals(""))
			        	{
			        		edificio2 = userInput2.getText().toString();
			        		
			        		for(int i = 0; i < edificios.length; i++)
				        		if(edificio2.toUpperCase().equals(edificios[i]))
				        		{
				        			lat1 = latitudes[i];
				        			lon1 = longitudes[i];
				        		}
			        		
			        		pointArrow = false; // los dos textfields tienen un ingreso valido
			        	}
			        	
			        	else
			        	{
			        		// solo un textfield tiene ingreso valido
			        		lat1 = gps.getLatitude();
			        		lon1 = gps.getLongitude();
			        	}
			        	
			        	double lat2 = -9999;
			        	double lon2 = -9999;
			        	String edificio = userInput.getText().toString();
			        	
			        	// se revisa si el primer textfield tiene un ingreso valido
			        	for(int i = 0; i < edificios.length; i++)
			        		if(edificio.toUpperCase().equals(edificios[i]))
			        		{
			        			lat2 = latitudes[i];
			        			lon2 = longitudes[i];
			        		}
			        	
			        	if(lat2 != -9999 && lon2 != -9999){
			        		// los edificios fueron validos y se pudo encontrar
			        		// sus coordenadas
			        		Location locationA = new Location("A");
			        		locationA.setLatitude(lat1);
			        		locationA.setLongitude(lon1);
			        		
			        		Location locationB = new Location("B");
			        		locationB.setLatitude(lat2);
			        		locationB.setLongitude(lon2);
			        		
			        		double distance = 0;
			        		
			        		String makeText = "";
			        		
			        		// makeText cambia su valor dependiendo de lo que el usuario pida
			        		if(pointArrow)
			        		{
			        			distance = getDistance(locationA, locationB);
			        			makeText = String.format("The distance is:\n %.2f meters.\n", distance);
			        		}
			        		
			        		else
			        		{
			        			// se encuetra el peso entre dos nodos (edificios) y el nodo central
			        			// para la universidad
			        			distance = matriz.getWeight(edificio, edificio2);
			        			if(distance == 1000)
			        			{
			        				distance = getDistance(locationA, locationB);
			        				makeText = String.format("The distance is:\n %.2f meters. " +
			        						"These buildings are not connected.\n" + 
			        						"The central building is: " + matriz.center(), distance);
			        			}
			        			else
			        				makeText = String.format("The distance is:\n %.2f meters.\n" + 
			        						"The central building is: " + matriz.center(), distance);
			        		}
			        				        		        		
			        		// Se muestra un mensaje con informacion
				        	Toast.makeText(getApplicationContext(), makeText , Toast.LENGTH_LONG).show();
				        	
				        	if(pointArrow)
				        	{	
				        		// si se desea mostrar la flecha, se calcula hacia donde debe ir el usuario
				        		// y se calcula el angulo donde se debe apuntar la flecha. Esto depende de
				        		// los sensores de ubicacion
				        		bearing = locationA.bearingTo(locationB);
				        		heading = (((float)bearing - getHeading()) * -1) + 90;
				        		
				        		// se rota la imagen X grados de su posicion inicial
				        		// los grados se calculan previo a esta instruccion
					        	RotateAnimation ra = new RotateAnimation(currentDegree, -heading,
					                    Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
	
					            // how long the animation will take place
					            ra.setDuration(210);
	
					            // set the animation after the end of the reservation status
					            ra.setFillAfter(true);

				            // Start the animation
					            image.setVisibility(View.VISIBLE);
					            image.startAnimation(ra);
					            currentDegree = -heading;
				        	}
				        	
			        	}else{
			        		// mensaje de error
			        		gps.showInputAlert();
			        		
			        		image.setVisibility(View.INVISIBLE);			        		
			        	}	        		
			        }else{
			        	// can't get location
			        	// GPS or Network is not enabled
			        	// Ask user to enable GPS/network in settings
			        	gps.showSettingsAlert();

		        		image.setVisibility(View.INVISIBLE);
			        }
		        }	
			
		        hideSoftKeyboard(MainActivity.this, arg0);
			}
		});
    }
	
	@Override
	// metodo que muestra un preview de la camara en pantalla
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height){
		// TODO Auto-generated method stub
		if(previewing){
			camera.stopPreview();
			previewing = false;
		}
		
		if (camera != null){
			try {
				camera.setPreviewDisplay(surfaceHolder);
				camera.startPreview();
				previewing = true;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	@Override
	// metodo que inicializa la camara
	public void surfaceCreated(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		camera = Camera.open();
	}

	@Override
	// metodo que apaga la camara
	public void surfaceDestroyed(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		try
		{
			camera.stopPreview();
			camera.release();
			camera = null;
			previewing = false;
		} catch(Exception e)
		{
			camera = null;
			previewing = false;
		}
	}
	
	// metodo que devuelve la distancia de una ubicacion a otra
	// las entradas son dos ubicaciones Location
	public double getDistance(Location locationA, Location locationB) {
	    double distance = 0;
	    distance = locationA.distanceTo(locationB);
	    return distance;
	}
    
	// metodo que esconde el teclado despues de que se termina de usar
    public static void hideSoftKeyboard (Activity activity, View view) 
    {
        InputMethodManager imm = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(view.getApplicationWindowToken(), 0);
    }

    @SuppressWarnings("deprecation")
	@Override
	// metodo que reinicia el sensor de orientacion
	// se uso un sensor que ya no se usa porque era mas facil de usar
	// que el metodo que se usa en las versiones mas nuevas de android
    protected void onResume() {
        super.onResume();
        
        // for the system's orientation sensor registered listeners
        mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
                SensorManager.SENSOR_DELAY_GAME);
    }
    
    @Override
    // apaga el sensor de ubicacion
    protected void onPause() {
        super.onPause();
        
        // to stop the listener and save battery
        mSensorManager.unregisterListener(this);
    }

    @Override
    // metodo que cambia el heading del usuario con base en su orientacion
    public void onSensorChanged(SensorEvent event) {

        // get the angle around the z-axis rotated
        heading = Math.round(event.values[0]);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}
    
    // metodo que devuelve el valor de heading
    public float getHeading()
    {
    	return heading;
    }
}

